﻿using System;
using System.IO;
using System.Net;
using System.Text;

namespace SharpBase.Web
{
    /// <summary>
    /// Encapsulates web interactions
    /// </summary>
    public class Web
    {
        private const string ALLOWED_URL_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";

        /// <summary>
        /// Posts a WebForm and returns the response data
        /// </summary>
        /// <param name="webForm">Web form to post</param>
        /// <returns>Returns a byte array containing the response data</returns>
        public static byte[] PostForm(WebForm webForm)
        {
            HttpWebRequest req = HttpWebRequest.Create(webForm.Uri) as HttpWebRequest;
            req.Method = "POST";
            req.ContentLength = webForm.ContentLength;
            req.ContentType = "application/x-www-form-urlencoded";
            req.ServicePoint.Expect100Continue = false;

            using (StreamWriter sw = new StreamWriter(req.GetRequestStream()))
                sw.Write(webForm.GetWebFormString());

            HttpWebResponse resp = req.GetResponse() as HttpWebResponse;

            using (MemoryStream ms = new MemoryStream())
            {
                using (Stream s = resp.GetResponseStream())
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead = s.Read(buffer, 0, 1024);
                    ms.Write(buffer, 0, bytesRead);
                    while (bytesRead > 0)
                    {
                        bytesRead = s.Read(buffer, 0, 1024);
                        ms.Write(buffer, 0, bytesRead);
                    }
                }

                resp.Close();
                return ms.ToArray();
            }
        }

        /// <summary>
        /// Performs a web request against the specified Web Form using the GET method
        /// </summary>
        /// <param name="webForm">Web form to request</param>
        /// <returns>Returns a byte array representing the response bytes</returns>
        public static byte[] GetForm(WebForm webForm)
        {
            string targetUri = webForm.Uri.ToString() + "?" + webForm.GetWebFormString();
            HttpWebRequest req = HttpWebRequest.Create(targetUri) as HttpWebRequest;
            req.Method = "GET";
            req.ServicePoint.Expect100Continue = false;

            HttpWebResponse resp = req.GetResponse() as HttpWebResponse;

            using (MemoryStream ms = new MemoryStream())
            {
                using (Stream s = resp.GetResponseStream())
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead = s.Read(buffer, 0, 1024);
                    ms.Write(buffer, 0, bytesRead);
                    while (bytesRead > 0)
                    {
                        bytesRead = s.Read(buffer, 0, 1024);
                        ms.Write(buffer, 0, bytesRead);
                    }
                }

                resp.Close();
                return ms.ToArray();
            }
        }

        /// <summary>
        /// "URL encodes" the input per RFC/OpenID specifications
        /// </summary>
        /// <param name="input">Input to be sanitized</param>
        /// <returns>Sanitized input</returns>
        public static string URLEncode(string input)
        {
            StringBuilder outputSb = new StringBuilder();
            for (int i = 0; i < input.Length; i++)
            {
                string curChar = input.Substring(i, 1);
                if (!ALLOWED_URL_CHARACTERS.Contains(curChar))
                {
                    byte charByte = Encoding.UTF8.GetBytes(curChar)[0];
                    string hexByte = charByte.ToString("X").ToUpper();
                    if (hexByte.Length == 1)
                        hexByte = "0" + hexByte;
                    outputSb.AppendFormat("%{0}", hexByte);
                }
                else
                    outputSb.Append(curChar);
            }
            return outputSb.ToString();
        }
    }
}
